using System.Data.Common;
using System.Net;
using System.Text.Json;
using Microsoft.Data.SqlClient;
using Oracle.ManagedDataAccess.Client;
using Lzfy_Refund_Service.Services;

namespace Lzfy_Refund_Service.Middleware
{
    /// <summary>
    /// 全局异常处理中间件
    /// </summary>
    public class GlobalExceptionHandlingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<GlobalExceptionHandlingMiddleware> _logger;
        private readonly IHostApplicationLifetime _appLifetime;
        private readonly IWebHostEnvironment _env;
        private readonly IServiceProvider _serviceProvider;
        
        // 数据库错误计数器
        private static int _consecutiveDbErrors = 0;
        private static DateTime _lastDbErrorResetTime = DateTime.Now;
        private static readonly object _errorCountLock = new object();
        private static readonly TimeSpan _dbErrorResetInterval = TimeSpan.FromMinutes(5);
        private const int _maxConsecutiveDbErrors = 20;
        
        // 异常统计
        private static readonly Dictionary<string, int> _exceptionCounts = new Dictionary<string, int>();
        private static DateTime _lastStatsResetTime = DateTime.Now;
        private static readonly TimeSpan _statsResetInterval = TimeSpan.FromHours(1);
        private const int _criticalExceptionThreshold = 10;

        public GlobalExceptionHandlingMiddleware(
            RequestDelegate next,
            ILogger<GlobalExceptionHandlingMiddleware> logger,
            IHostApplicationLifetime appLifetime,
            IWebHostEnvironment env,
            IServiceProvider serviceProvider)
        {
            _next = next;
            _logger = logger;
            _appLifetime = appLifetime;
            _env = env;
            _serviceProvider = serviceProvider;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                // 记录异常统计
                RecordExceptionStatistics(ex);
                
                _logger.LogError(ex, "全局异常处理: {ExceptionType} - {Message} - RequestPath: {RequestPath}", 
                    ex.GetType().Name, ex.Message, context.Request.Path);
                    
                await HandleExceptionAsync(context, ex);
                
                // 检查是否是数据库异常
                if (IsDbException(ex))
                {
                    HandleDatabaseException(ex);
                }
            }
        }

        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            context.Response.ContentType = "application/json";
            
            var (statusCode, errorMessage, errorType) = ClassifyException(exception);
            
            var response = new
            {
                error = new
                {
                    type = errorType,
                    message = errorMessage,
                    details = _env.IsDevelopment() ? exception.Message : "请联系系统管理员",
                    timestamp = DateTime.Now,
                    traceId = System.Diagnostics.Activity.Current?.Id ?? context.TraceIdentifier,
                    requestPath = context.Request.Path.Value
                }
            };

            // 检查是否为数据库相关异常
            if (IsDbException(exception))
            {
                HandleDatabaseException(exception);
                statusCode = 503; // Service Unavailable
            }
            else
            {
                // 重置数据库错误计数
                ResetDatabaseErrorCountIfNeeded();
            }

            context.Response.StatusCode = statusCode;

            var jsonResponse = JsonSerializer.Serialize(response, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });

            await context.Response.WriteAsync(jsonResponse);
        }

        /// <summary>
        /// 分类异常并返回相应的状态码和错误信息
        /// </summary>
        private (int statusCode, string errorMessage, string errorType) ClassifyException(Exception exception)
        {
            return exception switch
            {
                ArgumentException => (400, "请求参数错误", "ValidationError"),
                UnauthorizedAccessException => (401, "未授权访问", "AuthenticationError"),
                TimeoutException => (408, "请求超时", "TimeoutError"),
                NotImplementedException => (501, "功能未实现", "NotImplementedError"),
                _ when IsDbException(exception) => (503, "数据库服务暂时不可用", "DatabaseError"),
                _ => (500, "服务器内部错误", "InternalServerError")
            };
        }

        /// <summary>
        /// 重置数据库错误计数（如果需要）
        /// </summary>
        private void ResetDatabaseErrorCountIfNeeded()
        {
            lock (_errorCountLock)
            {
                if (DateTime.Now - _lastDbErrorResetTime > _dbErrorResetInterval)
                {
                    _consecutiveDbErrors = 0;
                }
            }
        }

        /// <summary>
        /// 判断是否为数据库异常
        /// </summary>
        private bool IsDbException(Exception ex)
        {
            return ex is DbException || // 通用数据库异常
                   ex is SqlException || // SQL Server异常
                   ex is OracleException || // Oracle异常
                   ex is TimeoutException || // 超时异常
                   (ex.InnerException != null && IsDbException(ex.InnerException));
        }

        /// <summary>
        /// 判断是否为关键SQL异常
        /// </summary>
        private bool IsCriticalSqlException(SqlException sqlException)
        {
            // SQL Server关键错误代码
            var criticalErrorNumbers = new[] { 2, 53, 18456, 1205, 8645, 8651 };
            return criticalErrorNumbers.Contains(sqlException.Number);
        }

        /// <summary>
        /// 判断是否为关键Oracle异常
        /// </summary>
        private bool IsCriticalOracleException(OracleException oracleException)
        {
            // Oracle关键错误代码
            var criticalErrorNumbers = new[] { 1017, 1033, 1034, 3113, 3114, 12154, 12505, 12514, 12541 };
            return criticalErrorNumbers.Contains(oracleException.Number);
        }

        /// <summary>
        /// 记录异常统计
        /// </summary>
        private void RecordExceptionStatistics(Exception exception)
        {
            lock (_errorCountLock)
            {
                var exceptionType = exception.GetType().Name;
                
                // 重置统计（如果需要）
                if (DateTime.Now - _lastStatsResetTime > _statsResetInterval)
                {
                    _exceptionCounts.Clear();
                    _lastStatsResetTime = DateTime.Now;
                }
                
                // 记录异常计数
                if (_exceptionCounts.ContainsKey(exceptionType))
                {
                    _exceptionCounts[exceptionType]++;
                }
                else
                {
                    _exceptionCounts[exceptionType] = 1;
                }
                
                // 检查是否达到关键阈值
                if (_exceptionCounts[exceptionType] >= _criticalExceptionThreshold)
                {
                    _logger.LogWarning("异常类型 {ExceptionType} 在过去1小时内发生了 {Count} 次", 
                        exceptionType, _exceptionCounts[exceptionType]);
                }
            }
        }

        /// <summary>
        /// 处理数据库异常
        /// </summary>
        private void HandleDatabaseException(Exception exception)
        {
            lock (_errorCountLock)
            {
                var now = DateTime.Now;
                
                // 如果距离上次数据库错误超过重置间隔，重置计数器
                if (now - _lastDbErrorResetTime > _dbErrorResetInterval)
                {
                    _consecutiveDbErrors = 0;
                }
                
                _lastDbErrorResetTime = now;
                _consecutiveDbErrors++;
                
                _logger.LogWarning(
                    "检测到数据库异常 (连续错误: {Count}/{Threshold}): {Message}",
                    _consecutiveDbErrors, _maxConsecutiveDbErrors, exception.Message);
                
                // 如果连续错误达到阈值，考虑采取更严格的措施
                if (_consecutiveDbErrors >= _maxConsecutiveDbErrors)
                {
                    _logger.LogCritical(
                        "数据库连续错误达到阈值 ({Count}次)，系统可能需要重启或进一步诊断",
                        _consecutiveDbErrors);
                    
                    // 在生产环境中，可以考虑通知管理员或自动重启应用
                    if (!_env.IsDevelopment())
                    {
                        // 触发数据库健康检查
                        TriggerDatabaseHealthCheck();
                        
                        _logger.LogCritical("由于持续的数据库错误，应用将在5秒后重启...");
                        
                        // 异步等待5秒后重启应用
                        Task.Run(async () => {
                            await Task.Delay(5000);
                            _appLifetime.StopApplication();
                        });
                    }
                    else
                    {
                        // 开发环境下只记录日志，不重启应用
                        _logger.LogWarning("开发环境下检测到数据库连续错误，但不会重启应用");
                    }
                    
                    // 重置计数器，避免重复触发
                    _consecutiveDbErrors = 0;
                }
            }
        }
        
        /// <summary>
        /// 触发数据库健康检查
        /// </summary>
        private void TriggerDatabaseHealthCheck()
        {
            try
            {
                // 获取数据库健康检查服务
                using var scope = _serviceProvider.CreateScope();
                var healthCheckService = scope.ServiceProvider.GetService<DatabaseHealthCheckService>();
                
                if (healthCheckService != null)
                {
                    // 获取当前健康状态
                    var healthStatus = healthCheckService.GetDatabasesHealth();
                    _logger.LogWarning(
                        "数据库健康状态: SQL Server: {SqlStatus}, Oracle: {OracleStatus}",
                        healthStatus.SqlServerHealthy ? "健康" : "不健康",
                        healthStatus.OracleHealthy ? "健康" : "不健康");
                }
                else
                {
                    _logger.LogWarning("未找到数据库健康检查服务");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "触发数据库健康检查时发生错误");
            }
        }
    }

    // 扩展方法，用于在Startup中注册中间件
    public static class GlobalExceptionHandlingMiddlewareExtensions
    {
        public static IApplicationBuilder UseGlobalExceptionHandling(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<GlobalExceptionHandlingMiddleware>();
        }
    }
}